package com.pllandxzx.handler;

import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * WebSocket初始化消息处理器
 * 处理WebSocket连接的建立、消息接收、连接关闭等事件
 * 实现了用户在线状态管理、消息广播和私聊功能
 */
public class MyHandler extends TextWebSocketHandler {

    // 存储所有在线用户的会话（线程安全），使用ConcurrentHashMap保证多线程环境下的安全性和效率
    private final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();

    // 记录在线用户数量，使用AtomicInteger保证原子性操作
    private final AtomicInteger onlineCount = new AtomicInteger(0);

    /**
     * 当WebSocket连接建立后调用
     * 处理用户连接逻辑，包括用户ID提取、在线状态管理和欢迎消息发送
     * @param session WebSocket会话对象
     * @throws Exception 处理过程中可能抛出的异常
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 从URI路径中提取用户ID（路径格式为/websocket/{userId}）
        String path = session.getUri().getPath();
        String userId = path.substring(path.lastIndexOf('/') + 1);

        // 验证用户ID有效性
        if (userId == null || userId.isEmpty()) {
            session.close(CloseStatus.BAD_DATA);
            return;
        }

        // 处理用户重复登录情况：若用户已在线，则关闭旧会话
        if (sessions.containsKey(userId)) {
            WebSocketSession oldSession = sessions.get(userId);
            if (oldSession.isOpen()) {
                oldSession.sendMessage(new TextMessage("您的账号在其他设备上登录，当前连接已断开"));
                oldSession.close(CloseStatus.NORMAL.withReason("账号在其他设备登录"));
            }
        }

        // 存储新会话并更新在线人数
        sessions.put(userId, session);
        int count = onlineCount.incrementAndGet();

        System.out.println("用户[" + userId + "]已连接，会话ID: " + session.getId());
        System.out.println("当前在线人数: " + count);

        // 向新连接用户发送欢迎消息
        session.sendMessage(new TextMessage("欢迎，用户" + userId + "！当前在线人数: " + count));

        // 广播用户上线通知（可选功能）
        broadcastMessage("系统通知: 用户" + userId + "上线了，当前在线人数: " + count);
    }

    /**
     * 处理接收到的文本消息
     * 区分私聊消息和广播消息，并执行相应的处理逻辑
     * @param session WebSocket会话对象
     * @param message 接收到的文本消息
     * @throws Exception 处理过程中可能抛出的异常
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        String userId = getUserId(session);

        System.out.println("收到用户[" + userId + "]的消息: " + payload);

        // 私聊消息处理（格式：/private 目标用户ID 消息内容）
        if (payload.startsWith("/private ")) {
            String[] parts = payload.split(" ", 3);
            if (parts.length == 3) {
                String targetUserId = parts[1];
                String privateMessage = parts[2];
                sendPrivateMessage(userId, targetUserId, privateMessage);
            } else {
                session.sendMessage(new TextMessage("私聊格式错误，请使用: /private 目标用户ID 消息内容"));
            }
        } else {
            // 普通消息处理：广播给所有在线用户
            broadcastMessage("用户" + userId + ": " + payload);
        }
    }

    /**
     * 当WebSocket连接关闭后调用
     * 处理用户下线逻辑，包括会话移除、在线人数更新和下线通知广播
     * @param session WebSocket会话对象
     * @param status 连接关闭状态
     * @throws Exception 处理过程中可能抛出的异常
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String userId = getUserId(session);
        if (sessions.remove(userId) != null) {
            int count = onlineCount.decrementAndGet();
            System.out.println("用户[" + userId + "]已断开连接，状态: " + status);
            System.out.println("当前在线人数: " + count);

            // 广播用户下线通知（可选功能）
            broadcastMessage("系统通知: 用户" + userId + "下线了，当前在线人数: " + count);
        }
    }

    /**
     * 处理WebSocket传输错误
     * 记录错误信息并关闭异常会话
     * @param session WebSocket会话对象
     * @param exception 捕获的异常对象
     * @throws Exception 处理过程中可能抛出的异常
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        String userId = getUserId(session);
        System.err.println("用户[" + userId + "]传输错误: " + exception.getMessage());
        exception.printStackTrace();

        // 发生错误时关闭会话
        if (session.isOpen()) {
            session.close(CloseStatus.SERVER_ERROR);
        }
    }

    /**
     * 从会话对象中提取用户ID
     * @param session WebSocket会话对象
     * @return 提取的用户ID
     */
    private String getUserId(WebSocketSession session) {
        String path = session.getUri().getPath();
        return path.substring(path.lastIndexOf('/') + 1);
    }

    /**
     * 向所有在线用户广播消息
     * @param message 要广播的消息内容
     */
    public void broadcastMessage(String message) {
        TextMessage textMessage = new TextMessage(message);
        for (WebSocketSession session : sessions.values()) {
            try {
                if (session.isOpen()) {
                    session.sendMessage(textMessage);
                }
            } catch (IOException e) {
                System.err.println("广播消息失败: " + e.getMessage());
            }
        }
    }

    /**
     * 向指定用户发送私聊消息
     * @param fromUserId 发送者ID
     * @param toUserId 接收者ID
     * @param message 消息内容
     */
    public void sendPrivateMessage(String fromUserId, String toUserId, String message) {
        WebSocketSession toSession = sessions.get(toUserId);
        if (toSession != null && toSession.isOpen()) {
            try {
                toSession.sendMessage(new TextMessage("来自用户" + fromUserId + "的私聊: " + message));

                // 向发送者确认消息已发送
                WebSocketSession fromSession = sessions.get(fromUserId);
                if (fromSession != null && fromSession.isOpen()) {
                    fromSession.sendMessage(new TextMessage("已向用户" + toUserId + "发送私聊: " + message));
                }
            } catch (IOException e) {
                System.err.println("发送私聊消息失败: " + e.getMessage());
            }
        } else {
            // 目标用户不在线，通知发送者
            WebSocketSession fromSession = sessions.get(fromUserId);
            if (fromSession != null && fromSession.isOpen()) {
                try {
                    fromSession.sendMessage(new TextMessage("用户" + toUserId + "不在线，消息发送失败"));
                } catch (IOException e) {
                    System.err.println("通知发送者失败: " + e.getMessage());
                }
            }
        }
    }

    /**
     * 获取所有在线用户的会话信息
     * @return 在线用户会话映射（用户ID -> 会话对象）
     */
    public Map<String, WebSocketSession> getOnlineSessions() {
        return sessions;
    }

    /**
     * 获取当前在线用户数量
     * @return 在线用户数
     */
    public int getOnlineCount() {
        return onlineCount.get();
    }
}